/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.scote.base.dao.impl;

import com.scote.base.dao.BaseDao;
import com.scote.base.model.ConditionInfo;
import com.scote.base.model.DataGrid;
import com.scote.base.model.PageInfo;
import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.Transformers;

/**
 *
 * @author YanPeng
 * @param <T>
 */
@SuppressWarnings("unchecked")
public class BaseDaoImpl<T> implements BaseDao<T> {

    @Resource(name = "sessionFactory")
    private SessionFactory sessionFactory;
    private final Class<?> clz;

    public BaseDaoImpl() {
        super();
        clz = (Class<?>) ((ParameterizedType) (getClass().getGenericSuperclass())).getActualTypeArguments()[0];
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    protected Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    /**
     * 插入一个对象
     *
     * @param t 要被持久化的对象
     * @return 持久化后的对象
     */
    @Override
    public T insert(T t) {
        getSession().save(t);
        return t;
    }

    /**
     * 更新一个对象
     *
     * @param t 要被持久化的对象
     */
    @Override
    public void update(T t) {
        getSession().update(t);
    }

    /**
     * 根据HQL语句更新对象
     *
     * @param hql 更新的HQL语句
     * @param args 参数组
     * @param alias 别名映射
     */
    @Override
    public void update(String hql, Object[] args, Map<String, Object> alias) {
        Query query = getSession().createQuery(hql);
        setAliasParameter(query, alias);
        setParameter(query, args);
        query.executeUpdate();
    }

    /**
     * 根据HQL语句更新对象
     *
     * @param hql 更新的HQL语句
     * @param alias 别名映射
     */
    @Override
    public void update(String hql, Map<String, Object> alias) {
        update(hql, null, alias);
    }

    /**
     * 根据HQL语句更新对象
     *
     * @param hql 更新的HQL语句
     * @param args 参数组
     */
    @Override
    public void update(String hql, Object[] args) {
        update(hql, args, null);
    }

    /**
     * 根据HQL语句更新对象
     *
     * @param hql 更新的HQL语句
     * @param arg 参数
     */
    @Override
    public void update(String hql, Object arg) {
        update(hql, new Object[]{arg});
    }

    /**
     * 根据HQL语句更新对象
     *
     * @param hql 更新的HQL语句
     */
    @Override
    public void update(String hql) {
        update(hql, null, null);
    }

    /**
     * 删除一个对象
     *
     * @param t 要被删除对象
     */
    @Override
    public void delete(T t) {
        getSession().delete(t);
    }

    /**
     * 根据ID删除一个对象
     *
     * @param id 要被删除对象的ID
     */
    @Override
    public void delete(long id) {
        getSession().delete(load(id));
    }

    /**
     * 获取一个对象
     *
     * @param id 要被加载对象的ID
     * @return 持久化的对象
     */
    @Override
    public T load(long id) {
        return (T) getSession().load(clz, id);
    }

    /**
     * 获取一个对象
     *
     * @param id 要被加载对象的ID
     * @return 持久化的对象
     */
    @Override
    public T get(long id) {
        return (T) getSession().get(clz, id);
    }

    /**
     * 根据HQL语句获取一个对象
     *
     * @param hql 要查询的HQL
     * @param args 参数组
     * @param alias 别名映射
     * @return 获取到的对象
     */
    @Override
    public T get(String hql, Object[] args, Map<String, Object> alias) {
        Query query = getSession().createQuery(hql);
        setAliasParameter(query, alias);
        setParameter(query, args);
        return (T) query.uniqueResult();
    }

    /**
     * 根据HQL语句获取一个对象
     *
     * @param hql 要查询的HQL
     * @param alias 别名映射
     * @return 获取到的对象
     */
    @Override
    public T get(String hql, Map<String, Object> alias) {
        return get(hql, null, alias);
    }

    /**
     * 根据HQL语句获取一个对象
     *
     * @param hql 要查询的HQL
     * @param args 参数组
     * @return 获取到的对象
     */
    @Override
    public T get(String hql, Object[] args) {
        return (T) get(hql, args, null);
    }

    /**
     * 根据HQL语句获取一个对象
     *
     * @param hql 要查询的HQL
     * @param arg 参数
     * @return 获取到的对象
     */
    @Override
    public T get(String hql, Object arg) {
        return get(hql, new Object[]{arg});
    }

    /**
     * 根据HQL语句获取一个对象
     *
     * @param hql 要查询的HQL
     * @return 获取到的对象
     */
    @Override
    public T get(String hql) {
        return get(hql, null, null);
    }

    /**
     * 根据HQL语句查询对象列表
     *
     * @param hql 要查询的HQL
     * @param args 参数组
     * @param alias 别名映射
     * @return 查询的结果列表
     */
    @Override
    public List<T> list(String hql, Object[] args, Map<String, Object> alias) {
        Query query = getSession().createQuery(hql);
        setAliasParameter(query, alias);
        setParameter(query, args);
        return query.list();
    }

    /**
     * 根据HQL语句查询对象列表
     *
     * @param hql 要查询的HQL
     * @param alias 别名映射
     * @return 查询的结果列表
     */
    @Override
    public List<T> list(String hql, Map<String, Object> alias) {
        return list(hql, null, alias);
    }

    /**
     * 根据HQL语句查询对象列表
     *
     * @param hql 要查询的HQL
     * @param args 参数组
     * @return 查询的结果列表
     */
    @Override
    public List<T> list(String hql, Object[] args) {
        return list(hql, args, null);
    }

    /**
     * 根据HQL语句查询对象列表
     *
     * @param hql 要查询的HQL
     * @param arg 参数
     * @return 查询的结果列表
     */
    @Override
    public List<T> list(String hql, Object arg) {
        return list(hql, new Object[]{arg}, null);
    }

    /**
     * 根据HQL语句查询对象列表
     *
     * @param hql 要查询的HQL
     * @return 查询的结果列表
     */
    @Override
    public List<T> list(String hql) {
        return list(hql, null, null);
    }

    /**
     * 根据HQL语句统计数量
     *
     * @param hql
     * @param args
     * @param alias
     * @return 数量
     */
    @Override
    public long count(String hql, Object[] args, Map<String, Object> alias) {
        Query query = getSession().createQuery(hql);
        setAliasParameter(query, alias);
        setParameter(query, args);
        Long total = (Long) query.uniqueResult();
        return (total == null) ? 0 : total;
    }

    /**
     * 根据HQL语句统计数量
     *
     * @param hql 要查询的HQL
     * @param alias 别名映射
     * @return 数量
     */
    @Override
    public long count(String hql, Map<String, Object> alias) {
        return count(hql, null, alias);
    }

    /**
     * 根据HQL语句统计数量
     *
     * @param hql 要查询的HQL
     * @param args 参数组
     * @return 数量
     */
    @Override
    public long count(String hql, Object[] args) {
        return count(hql, args, null);
    }

    /**
     * 根据HQL语句统计数量
     *
     * @param hql 要查询的HQL
     * @param arg 参数
     * @return 数量
     */
    @Override
    public long count(String hql, Object arg) {
        return count(hql, new Object[]{arg});
    }

    /**
     * 根据HQL语句统计数量
     *
     * @param hql 要查询的HQL
     * @return 数量
     */
    @Override
    public long count(String hql) {
        return count(hql, null, null);
    }

    /**
     * 根据SQL语句查询对象列表
     *
     * @param <N> 返回的对象类型
     * @param sql 查询SQL语句
     * @param args 参数组
     * @param alias 别名映射
     * @param hasEntity 是否是映射实体
     * @return 查询对象列表
     */
    @Override
    public <N extends Object> List<N> listBySql(String sql, Object[] args, Map<String, Object> alias, boolean hasEntity) {
        SQLQuery sq = getSession().createSQLQuery(sql);
        setAliasParameter(sq, alias);
        setParameter(sq, args);
        if (hasEntity) {
            sq.addEntity(clz);
        } else {
            sq.setResultTransformer(Transformers.aliasToBean(clz));
        }
        return sq.list();
    }

    /**
     * 根据SQL语句查询对象列表
     *
     * @param <N> 返回的对象类型
     * @param sql 查询SQL语句
     * @param alias 别名映射
     * @param hasEntity 是否是映射实体
     * @return 查询对象列表
     */
    @Override
    public <N extends Object> List<N> listBySql(String sql, Map<String, Object> alias, boolean hasEntity) {
        return listBySql(sql, null, alias, hasEntity);
    }

    /**
     * 根据SQL语句查询对象列表
     *
     * @param <N> 返回的对象类型
     * @param sql 查询SQL语句
     * @param args 参数组
     * @param hasEntity 是否是映射实体
     * @return 查询对象列表
     */
    @Override
    public <N extends Object> List<N> listBySql(String sql, Object[] args, boolean hasEntity) {
        return listBySql(sql, args, null, hasEntity);
    }

    /**
     * 根据SQL语句查询对象列表
     *
     * @param <N> 返回的对象类型
     * @param sql 查询SQL语句
     * @param arg 参数
     * @param hasEntity 是否是映射实体
     * @return 查询对象列表
     */
    @Override
    public <N extends Object> List<N> listBySql(String sql, Object arg, boolean hasEntity) {
        return listBySql(sql, new Object[]{arg}, hasEntity);
    }

    /**
     * 根据SQL语句查询对象列表
     *
     * @param <N> 返回的对象类型
     * @param sql 查询SQL语句
     * @param hasEntity 是否是映射实体
     * @return 查询对象列表
     */
    @Override
    public <N extends Object> List<N> listBySql(String sql, boolean hasEntity) {
        return listBySql(sql, null, null, hasEntity);
    }

    /**
     * 根据SQL语句统计数量
     *
     * @param sql 查询SQL语句
     * @param args 参数组
     * @param alias 别名映射
     * @param hasEntity 是否是映射实体
     * @return 数量
     */
    @Override
    public long countBySql(String sql, Object[] args, Map<String, Object> alias, boolean hasEntity) {
        SQLQuery query = getSession().createSQLQuery(sql);
        setAliasParameter(query, alias);
        setParameter(query, args);
        if (hasEntity) {
            query.addEntity(clz);
        } else {
            query.setResultTransformer(Transformers.aliasToBean(clz));
        }
        Long total = (Long) query.uniqueResult();
        return (total == null) ? 0 : total;
    }

    /**
     * 根据SQL语句统计数量
     *
     * @param sql 查询SQL语句
     * @param alias 别名映射
     * @param hasEntity 是否是映射实体
     * @return 数量
     */
    @Override
    public long countBySql(String sql, Map<String, Object> alias, boolean hasEntity) {
        return countBySql(sql, null, alias, hasEntity);
    }

    /**
     * 根据SQL语句统计数量
     *
     * @param sql 查询SQL语句
     * @param args 参数组
     * @param hasEntity 是否是映射实体
     * @return 数量
     */
    @Override
    public long countBySql(String sql, Object[] args, boolean hasEntity) {
        return countBySql(sql, args, null, hasEntity);
    }

    /**
     * 根据SQL语句统计数量
     *
     * @param sql 查询SQL语句
     * @param arg 参数
     * @param hasEntity 是否是映射实体
     * @return 数量
     */
    @Override
    public long countBySql(String sql, Object arg, boolean hasEntity) {
        return countBySql(sql, new Object[]{arg}, hasEntity);
    }

    /**
     * 根据SQL语句统计数量
     *
     * @param sql 查询SQL语句
     * @param hasEntity 是否是映射实体
     * @return 数量
     */
    @Override
    public long countBySql(String sql, boolean hasEntity) {
        return countBySql(sql, null, null, hasEntity);
    }

    /**
     * 获取DataGrid信息
     *
     * @param pageInfo 分页信息
     * @param example 模糊查询条件
     * @param conditions DataGrid信息
     * @return
     */
    @Override
    public DataGrid dataGrid(PageInfo pageInfo, final Object example, List<ConditionInfo> conditions) {
        DataGrid dataGrid = new DataGrid();
        Criteria queryCriteria = getSession().createCriteria(clz);
        Criteria countCriteria = getSession().createCriteria(clz);
        if (example != null) {
            queryCriteria.add(Example.create(example).enableLike().ignoreCase());
            countCriteria.add(Example.create(example).enableLike().ignoreCase());
        }
        if (conditions != null && !conditions.isEmpty()) {
            for (ConditionInfo conditionInfo : conditions) {
                switch (conditionInfo.getCondition()) {
                    case EQ:
                        queryCriteria.add(Restrictions.eq(conditionInfo.getField(), conditionInfo.getValue()));
                        countCriteria.add(Restrictions.eq(conditionInfo.getField(), conditionInfo.getValue()));
                        break;
                    case GT:
                        queryCriteria.add(Restrictions.gt(conditionInfo.getField(), conditionInfo.getValue()));
                        countCriteria.add(Restrictions.gt(conditionInfo.getField(), conditionInfo.getValue()));
                        break;
                    case GE:
                        queryCriteria.add(Restrictions.ge(conditionInfo.getField(), conditionInfo.getValue()));
                        countCriteria.add(Restrictions.ge(conditionInfo.getField(), conditionInfo.getValue()));
                        break;
                    case LT:
                        queryCriteria.add(Restrictions.lt(conditionInfo.getField(), conditionInfo.getValue()));
                        countCriteria.add(Restrictions.lt(conditionInfo.getField(), conditionInfo.getValue()));
                        break;
                    case LE:
                        queryCriteria.add(Restrictions.le(conditionInfo.getField(), conditionInfo.getValue()));
                        countCriteria.add(Restrictions.le(conditionInfo.getField(), conditionInfo.getValue()));
                        break;
                    case LIKE:
                        queryCriteria.add(Restrictions.like(conditionInfo.getField(), conditionInfo.getValue()));
                        countCriteria.add(Restrictions.like(conditionInfo.getField(), conditionInfo.getValue()));
                        break;
                }
            }
        }
        if ("desc".equalsIgnoreCase(pageInfo.getOrder())) {
            queryCriteria.addOrder(Order.desc(pageInfo.getSort()));
        } else {
            queryCriteria.addOrder(Order.asc(pageInfo.getSort()));
        }
        queryCriteria.setFirstResult(pageInfo.getStartRow());
        queryCriteria.setMaxResults(pageInfo.getRows());
        dataGrid.setRows(queryCriteria.list());
        countCriteria.setProjection(Projections.count("id"));
        Long total = (Long) countCriteria.uniqueResult();
        dataGrid.setTotal((total == null) ? 0 : total);
        return dataGrid;
    }

    /**
     * 获取DataGrid信息
     *
     * @param pageInfo 分页信息
     * @param example 模糊查询条件
     * @return DataGrid信息
     */
    @Override
    public DataGrid dataGrid(PageInfo pageInfo, final Object example) {
        return dataGrid(pageInfo, example, null);
    }

    //设置别名
    @SuppressWarnings("rawtypes")
    private void setAliasParameter(Query query, Map<String, Object> alias) {
        if (alias != null) {
            Set<String> keys = alias.keySet();
            for (String key : keys) {
                Object val = alias.get(key);
                if (val instanceof Collection) {//查询条件是列表
                    query.setParameterList(key, (Collection) val);
                } else {
                    query.setParameter(key, val);
                }
            }
        }
    }

    //设置参数
    private void setParameter(Query query, Object[] args) {
        if (args != null && args.length > 0) {
            int index = 0;
            for (Object arg : args) {
                query.setParameter(index++, arg);
            }
        }
    }
}
